﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SimpleServiceBus.Endpoints.ActiveMQ.Configuration;
using SimpleServiceBus.Endpoint;
using SimpleServiceBus.Endpoints.ActiveMQ.Transport;
using Sample.Messages;
using System.IO;

namespace SampleProducer {
    public partial class Form1: Form {
        private IMessagingEndpoint fEndpoint;

        public Form1() {
            InitializeComponent();
            Logger.TextLogged += Logger_TextLogged;
            foreach(var _button in GetActions())
                _button.Enabled = false;
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
            if(fEndpoint != null) {
                fEndpoint.Stop();
                fEndpoint = null;
            }
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e) {
            Logger.TextLogged -= Logger_TextLogged;
        }

        private void Logger_TextLogged(string message) {
            if(this.InvokeRequired) {
                Action<String> _callback = Logger_TextLogged;
                this.Invoke(_callback, message);
            }
            else {
                if(txtLog.Text != null && txtLog.Text.Length > 128 * 1024)
                    txtLog.Text = "";
                txtLog.Text += String.Format("[{0:HH:mm:ss}] {1}{2}", DateTime.Now, message, Environment.NewLine);
                txtLog.SelectionStart = txtLog.Text.Length;
                txtLog.SelectionLength = 0;
                txtLog.ScrollToCaret();
            }
        }

        private ActiveMQConfigurator CreateConfigurator() {
            return new ActiveMQConfigurator("ActiveMQ.SampleProducer", "Samples.Producer")
                .ConnectTo(txtBrokerUrl.Text)
                //.UseCrendentials("myuser", "mypwd")
                //.FormatMessagesUsing(MessageFormat.Binary) // Text is the default format
                .SetupDefaultConsumerPool(x => {
                    x.WorkerCount = 5;
                    x.ConsumeQueue("Samples.Simple");
                })
                .SetupConsumerPool("PingPong", x => {
                    x.WorkerCount = 1;
                    x.ConsumeQueue("Samples.Pong");
                })
                .SetupMessageHandlers(x => {
                    x.Register(this.GetType().Assembly);
                })
                .SetupMessageDestinations(x => {
                    x.Send(typeof(PingPong), "Samples.Ping");
                    x.Send(typeof(SimpleMessage), "Samples.Simple");
                    x.Send(typeof(SquareRequest), "Samples.Consumer");
                    x.Send(typeof(SquareResponse), "Samples.Producer");
                    x.Send(typeof(PictureMessage), "Samples.Consumer");
                    x.Send(typeof(BadMessage), "Samples.Consumer");
                    //x.Send(typeof(LogMessage), "Samples.Consumer, Samples.Producer"); Note that you can specify multiple destinations  within the destination string too
                    x.Send(typeof(LogMessage), "Samples.Consumer", "Samples.Producer"); // Note that the message will be sent once to ActiveMQ, but ActiveMQ will multiplex to the specified destinations efficiently.

                    x.Publish<Area1>();
                    x.Publish<Area2>();
                    x.Publish<Area3>("Samples.HardcodedArea3");
                    x.Publish<Area4>(); // this will automatically publish on the 'Other.Area4' topic because Area4 inherits from OtherTopic 
                                        // which is decorated with [Topic(TopicName="Other")]
                                        // then a consumer can subscribe to any topic that inherits from the base class using:
                                        // x.Subscribe("Other.>");
                });
        }

        private IMessagingEndpoint CreateEndpoint() {
            var _configurator = CreateConfigurator();
            var _result = _configurator.CreateEndpoint();
            _result.EndpointOnline += Handle_EndpointOnline;
            _result.EndpointOffline += Handle_EndpointOffline;
            _result.MessageBus.MessageProcessingException += new EventHandler<SimpleServiceBus.Bus.MessageProcessingErrorEventArgs>(MessageBus_MessageProcessingException);
            return _result;
        }

        private void MessageBus_MessageProcessingException(object sender, SimpleServiceBus.Bus.MessageProcessingErrorEventArgs e) {
            Logger.Log("An exception occurred while processing a message: {0}", e.Exception.Message);
        }

        private void Handle_EndpointOnline(object sender, EndpointEventArgs e) {
            Logger.Log("Endpoint online");
            foreach(var _button in GetActions())
                _button.Enabled = true;
        }

        private void Handle_EndpointOffline(object sender, EndpointEventArgs e) {
            Logger.Log("Endpoint offline");
            foreach(var _button in GetActions())
                _button.Enabled = false;
        }

        private Button[] GetActions() {
            return new Button[] {
                btnStartPingPong,
                btnSendInBatch,
                btnCalcSquare,
                btnSendPicture,
                btnSendBadMessage,
                btnSendTopic1,
                btnSendTopic2,
                btnSendTopic3,
                btnSendTopic4,
                btnSendLog
            };
        }

        private void btnStart_Click(object sender, EventArgs e) {
            fEndpoint = CreateEndpoint();
            fEndpoint.Start();
            btnStart.Enabled = false;
            btnStop.Enabled = true;
        }

        private void btnStop_Click(object sender, EventArgs e) {
            if(fEndpoint != null) {
                fEndpoint.Stop();
                fEndpoint = null;
            }
            btnStart.Enabled = true;
            btnStop.Enabled = false;
        }

        private void btnStartPingPong_Click(object sender, EventArgs e) {
            var _message = new PingPong {
                StartTime = DateTime.UtcNow,
                MaxIterations = Convert.ToInt32(txtPingPongIterations.Text),
                Data = new String('*', 1024*256)
            };
            Logger.Log("Starting Ping/Pong with {0} iterations", _message.MaxIterations);
            fEndpoint.MessageBus.Send(_message);
        }

        private void btnSendInBatch_Click(object sender, EventArgs e) {
            var _messages = new List<object>();
            for(Int32 i = 0; i < Convert.ToInt32(txtMessageCount.Text); i++) {
                var _message = new SimpleMessage();
                _message.Value = i;
                if(!String.IsNullOrEmpty(txtMessageGroupId.Text)) {
                    // will be automatically used by the activemq transport and injected as a JMSXGroupID attribute.
                    // see http://activemq.apache.org/message-groups.html
                    _message.MessageGroupId = txtMessageGroupId.Text;
                }
                _messages.Add(_message);
            }
            if(chkFailInTheMiddleOfTheBatch.Checked)
                _messages.Insert(_messages.Count / 2, new UnboundMessage());
            var _bus = (IExtendedMessageBus)fEndpoint.MessageBus;
            try {
                _bus.Send(_messages);
            }
            catch(Exception _error) {
                Logger.Log("Caught exception while sending in batch: {0}", _error.Message);
            }
        }

        private void btnCalcSquare_Click(object sender, EventArgs e) {
            var _request = new SquareRequest {
                Value = Convert.ToInt32(txtSquareArg.Text),
                DoNotAnswer = chkForceRequestToExpire.Checked
            };
            Logger.Log("Requesting square of {0}", _request.Value);
            var _bus = (IExtendedMessageBus)fEndpoint.MessageBus;
            var _response = (SquareResponse)_bus.Ask(_request, TimeSpan.FromSeconds(10));
            if(_response != null)
                Logger.Log("Received response: square of {0} = {1}", _request.Value, _response.Result);
            else
                Logger.Log("Request timed out!");
        }

        private void btnSendPicture_Click(object sender, EventArgs e) {
            var _message = new PictureMessage {
                FileName = txtImageFileName.Text,
                Bytes = File.ReadAllBytes(txtImageFileName.Text),
                BinaryStream = "Image",
                Comments = new String[] { "Comment1", "Comment2", "Comment3" }
            };
            Logger.Log("Sending picture {0}", _message.FileName);
            fEndpoint.MessageBus.Send(_message);
        }

        private void btnSendBadMessage_Click(object sender, EventArgs e) {
            Logger.Log("Sending bad message");
            fEndpoint.MessageBus.Send(new BadMessage());
        }

        private void btnSendTopic1_Click(object sender, EventArgs e) {
            Logger.Log("Publishing Area1 topic");
            var _topic = new Area1 { MainValue = "Foo", IntValue = 33 };
            if(chkUseUnexpectedMain.Checked)
                _topic.MainValue = "Unexpected";
            fEndpoint.MessageBus.Send(_topic);
        }

        private void btnSendTopic2_Click(object sender, EventArgs e) {
            Logger.Log("Publishing Area2 topic");
            fEndpoint.MessageBus.Send(new Area2 { MainValue = "Foo", DoubleValue = 3.14 });
        }

        private void btnSendTopic3_Click(object sender, EventArgs e) {
            Logger.Log("Publishing Area3 topic");
            fEndpoint.MessageBus.Send(new Area3 { MainValue = "Bar", BoolValue = true});
        }

        private void btnSendTopic4_Click(object sender, EventArgs e) {
            Logger.Log("Publishing Area4 topic");
            fEndpoint.MessageBus.Send(new Area4 { OtherValue = "FooBar", Value = "Hello" });
        }

        private void btnSendLog_Click(object sender, EventArgs e) {
            var _log = new LogMessage { Text = "Time is " + DateTime.Now.ToString() };
            fEndpoint.MessageBus.Send(_log);
        }

    }
}
